package com.songlanyun.modules.pay.common.util;

import cn.hutool.json.JSONUtil;
import com.songlanyun.pay.bean.RefundModel;
import com.songlanyun.pay.common.util.*;
import com.songlanyun.pay.configure.WxPayConfig;
import java.math.BigDecimal;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class WxPayManager {
    private static final Logger log = LoggerFactory.getLogger(com.songlanyun.pay.common.util.WxPayManager.class);

    @Autowired
    private WxPayConfig wxPayConfig;

    public WxPayManager() {
    }

    public static Map<String, String> createNativeOrder(WxPayConfig wxPayConfig, String orderNo, int amount, String ip) throws Exception {
        Map<String, String> dataMap = new HashMap(16);
        dataMap.put("appid", wxPayConfig.getAppId());
        dataMap.put("mch_id", wxPayConfig.getMchId());
        dataMap.put("nonce_str", UUIDUtil.getUUID());
        dataMap.put("body", wxPayConfig.getBody());
        dataMap.put("out_trade_no", orderNo);
        dataMap.put("total_fee", String.valueOf(amount));
        dataMap.put("spbill_create_ip", ip);
        dataMap.put("notify_url", wxPayConfig.getNotifyUrl());
        dataMap.put("trade_type", wxPayConfig.getTradeTypeNative());
        Map<String, String> responseMap = signAndGetResponse(dataMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign(), wxPayConfig.getUnifiedOrderUrl());
        if (responseMap != null && !responseMap.isEmpty()) {
            responseMap.put("pre_pay_order_status", wxPayConfig.getResponseSuccess());
            return responseMap;
        } else {
            return null;
        }
    }

    public static Map<String, String> createJsAPIOrder(WxPayConfig wxPayConfig, String orderNo, int amount, String ip, String openId) throws Exception {
        Map<String, String> dataMap = new HashMap(16);
        dataMap.put("appid", wxPayConfig.getPublicAppId());
        dataMap.put("mch_id", wxPayConfig.getMchId());
        dataMap.put("nonce_str", UUIDUtil.getUUID());
        dataMap.put("body", wxPayConfig.getBody());
        dataMap.put("out_trade_no", orderNo);
        dataMap.put("total_fee", String.valueOf(amount));
        dataMap.put("spbill_create_ip", ip);
        dataMap.put("notify_url", wxPayConfig.getNotifyUrl());
        dataMap.put("trade_type", wxPayConfig.getTradeTypeJsApi());
        dataMap.put("openid", openId);
        Map<String, String> responseMap = signAndGetResponse(dataMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign(), wxPayConfig.getUnifiedOrderUrl());
        if (responseMap != null && !responseMap.isEmpty()) {
            Map<String, String> resultMap = getJsApiPayOrder(responseMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign(), "prepay_id=" + (String)responseMap.get("prepay_id"), wxPayConfig.getSignType());
            resultMap.put("pre_pay_order_status", wxPayConfig.getResponseSuccess());
            return resultMap;
        } else {
            return null;
        }
    }

    public static Map<String, String> createH5Order(WxPayConfig wxPayConfig, String orderNo, int amount, String ip) throws Exception {
        Map<String, String> dataMap = new HashMap(16);
        dataMap.put("appid", wxPayConfig.getPublicAppId());
        dataMap.put("mch_id", wxPayConfig.getMchId());
        dataMap.put("nonce_str", UUIDUtil.getUUID());
        dataMap.put("body", wxPayConfig.getBody());
        dataMap.put("out_trade_no", orderNo);
        dataMap.put("total_fee", String.valueOf(amount));
        dataMap.put("spbill_create_ip", ip);
        dataMap.put("notify_url", wxPayConfig.getNotifyUrl());
        dataMap.put("trade_type", wxPayConfig.getTradeTypeH5());
        dataMap.put("scene_info", "{\"h5_info\": {\"type\":\"WAP\",\"wap_url\": \"" + wxPayConfig.getWapUrl() + ",\"wap_name\": " + wxPayConfig.getBody() + "}}");
        Map<String, String> responseMap = signAndGetResponse(dataMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign(), wxPayConfig.getUnifiedOrderUrl());
        if (responseMap != null && !responseMap.isEmpty()) {
            responseMap.put("pre_pay_order_status", wxPayConfig.getResponseSuccess());
            return responseMap;
        } else {
            return null;
        }
    }

    public static Map<String, String> createAppOrder(WxPayConfig wxPayConfig, String orderNo, int amount, String ip, String description) throws Exception {
        Map<String, String> dataMap = new HashMap(16);
        dataMap.put("appid", wxPayConfig.getAppId());
        dataMap.put("mch_id", wxPayConfig.getMchId());
        dataMap.put("nonce_str", UUIDUtil.getUUID());
        dataMap.put("body", StringUtils.isEmpty(description) ? wxPayConfig.getBody() : description);
        dataMap.put("out_trade_no", orderNo);
        dataMap.put("total_fee", String.valueOf(amount));
        dataMap.put("spbill_create_ip", ip);
        dataMap.put("notify_url", wxPayConfig.getNotifyUrl());
        dataMap.put("trade_type", wxPayConfig.getTradeTypeApp());
        Map<String, String> responseMap = signAndGetResponse(dataMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign(), wxPayConfig.getUnifiedOrderUrl());
        if (responseMap != null && !responseMap.isEmpty()) {
            Map<String, String> resultMap = getAppPayOrder(responseMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign(), wxPayConfig.getPackageApp());
            resultMap.put("pre_pay_order_status", wxPayConfig.getResponseSuccess());
            return resultMap;
        } else {
            return null;
        }
    }

    public static Map<String, String> createMiniOrder(WxPayConfig wxPayConfig, String orderNo, int amount, String ip, String openId, String body) throws Exception {
        Map<String, String> dataMap = new HashMap(16);
        dataMap.put("appid", wxPayConfig.getMiniAppId());
        dataMap.put("mch_id", wxPayConfig.getMchId());
        dataMap.put("nonce_str", UUIDUtil.getUUID());
        dataMap.put("sign_type", wxPayConfig.getSignType());
        dataMap.put("body", StringUtils.isEmpty(body) ? wxPayConfig.getBody() : body);
        dataMap.put("out_trade_no", orderNo);
        dataMap.put("total_fee", String.valueOf(amount));
        dataMap.put("spbill_create_ip", ip);
        dataMap.put("notify_url", wxPayConfig.getNotifyUrl());
        dataMap.put("trade_type", wxPayConfig.getTradeTypeJsApi());
        dataMap.put("openid", openId);
        Map<String, String> responseMap = signAndGetResponse(dataMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign(), wxPayConfig.getUnifiedOrderUrl());
        if (responseMap != null && !responseMap.isEmpty()) {
            Map<String, String> resultMap = getJsApiPayOrder(responseMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign(), "prepay_id=" + (String)responseMap.get("prepay_id"), wxPayConfig.getSignType());
            resultMap.put("pre_pay_order_status", wxPayConfig.getResponseSuccess());
            return resultMap;
        } else {
            return null;
        }
    }

    public static Map<String, String> getPayResult(WxPayConfig wxPayConfig, String orderNo) throws Exception {
        Map<String, String> dataMap = new HashMap(16);
        dataMap.put("appid", wxPayConfig.getAppId());
        dataMap.put("mch_id", wxPayConfig.getMchId());
        dataMap.put("out_trade_no", orderNo);
        dataMap.put("nonce_str", UUIDUtil.getUUID());
        String md5Sign = SignUtil.getMD5Sign(dataMap, wxPayConfig.getKey(), wxPayConfig.getFieldSign());
        dataMap.put("sign", md5Sign);
        String respXml = HttpClientUtil.requestWithoutCert(wxPayConfig.getOrderQueryUrl(), dataMap, 5000, 10000);
        dataMap.clear();
        dataMap = processResponseXml(respXml, wxPayConfig.getKey(), wxPayConfig.getFieldSign());
        log.info(dataMap.toString());
        Map<String, String> resultMap = new HashMap(16);
        if (!StringUtils.isEmpty(dataMap.get("trade_state"))) {
            resultMap.put("tradeState", dataMap.get("trade_state"));
        }

        if (!StringUtils.isEmpty(dataMap.get("transaction_id"))) {
            resultMap.put("payNo", dataMap.get("transaction_id"));
        }

        resultMap.put("payType", "WxPay");
        return resultMap;
    }

    private static Map<String, String> signAndGetResponse(Map<String, String> dataMap, String key, String signField, String apiUrl) throws Exception {
        String md5Sign = SignUtil.getMD5Sign(dataMap, key, signField);
        dataMap.put("sign", md5Sign);
        String respXml = HttpClientUtil.requestWithoutCert(apiUrl, dataMap, 5000, 10000);
        dataMap.clear();
        dataMap = processResponseXml(respXml, key, signField);
        log.info(dataMap.toString());
        if (StringUtils.isEmpty(dataMap.get("prepay_id"))) {
            throw new RuntimeException("此通道暂停支付，请选择其他支付方式");
        } else {
            return dataMap;
        }
    }

    private static Map<String, String> processResponseXml(String xmlStr, String key, String signField) throws Exception {
        String returnCodeField = "return_code";
        String resultFail = "FAIL";
        String resultSuccess = "SUCCESS";
        Map<String, String> respData = MapUtil.xml2Map(xmlStr);
        if (respData.containsKey(returnCodeField)) {
            String returnCode = (String)respData.get(returnCodeField);
            if (returnCode.equalsIgnoreCase(resultFail)) {
                return respData;
            } else if (returnCode.equalsIgnoreCase(resultSuccess)) {
                if (SignUtil.signValidate(respData, key, signField)) {
                    return respData;
                } else {
                    throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr));
                }
            } else {
                throw new Exception(String.format("return_code value %s is invalid in XML: %s", returnCode, xmlStr));
            }
        } else {
            throw new Exception(String.format("No `return_code` in XML: %s", xmlStr));
        }
    }

    private static Map<String, String> getAppPayOrder(Map<String, String> data, String key, String fieldSign, String packageStr) throws Exception {
        Map<String, String> resultMap = new HashMap(16);
        resultMap.put("appid", data.get("appid"));
        resultMap.put("partnerid", data.get("mch_id"));
        resultMap.put("prepayid", data.get("prepay_id"));
        resultMap.put("package", packageStr);
        resultMap.put("noncestr", UUIDUtil.getUUID());
        resultMap.put("timestamp", DateUtil.getTimeStampSecond());
        String sign = SignUtil.getMD5Sign(resultMap, key, fieldSign);
        resultMap.put("sign", sign);
        return resultMap;
    }

    private static Map<String, String> getJsApiPayOrder(Map<String, String> data, String key, String fieldSign, String packageStr, String signType) throws Exception {
        Map<String, String> resultMap = new HashMap(16);
        resultMap.put("appId", data.get("appid"));
        resultMap.put("timeStamp", DateUtil.getTimeStampSecond());
        resultMap.put("nonceStr", UUIDUtil.getUUID());
        resultMap.put("package", packageStr);
        resultMap.put("signType", signType);
        String sign = SignUtil.getMD5Sign(resultMap, key, fieldSign);
        resultMap.put("paySign", sign);
        return resultMap;
    }

    public static String wxRefund(WxPayConfig wxPayConfig, RefundModel refundModel, Function callBack) {
        String xmlStr = "";
        String resultXml = "";
        new HashMap();
        double refundFee = refundModel.getRefundAmount().doubleValue();
        double totalFee = refundModel.getTotalFee().doubleValue();
        String total_fee = Integer.toString((int)(totalFee * 100.0));
        String refund_fee = Integer.toString((int)(refundFee * 100.0));
        String refund_desc = refundModel.getRefundReason();
        Map<String, String> map = new HashMap();
        map.put("appid", wxPayConfig.getAppId());
        map.put("mch_id", wxPayConfig.getMchId());
        map.put("nonce_str", UUIDUtil.getUUID());
        map.put("transaction_id", refundModel.getTradeNo());
        map.put("out_refund_no", refundModel.getRefundNo());
        map.put("out_trade_no", refundModel.getOrderNo());
        map.put("total_fee", total_fee);
        map.put("refund_fee", refund_fee);
        map.put("refund_desc", refund_desc);
        map.put("notify_url", wxPayConfig.getCallFunc());

        Map resultMap;
        try {
            xmlStr = SignUtil.getMD5Sign(map, wxPayConfig.getKey(), wxPayConfig.getFieldSign());
            map.put("sign", xmlStr);
            resultXml = ClientCustomSSL.doRefund(wxPayConfig, MapUtil.mapToXml(map));
            resultMap = MapUtil.xml2Map(resultXml);
        } catch (Exception var15) {
            Exception e = var15;
            log.debug("调用退款接口失败");
            return e.getMessage();
        }

        if (((String)resultMap.get("return_code")).equals(wxPayConfig.getResponseSuccess()) && ((String)resultMap.get("result_code")).equals(wxPayConfig.getResponseSuccess())) {
            log.debug("退款申请成功");
            callBack.apply(resultMap);
            return "success";
        } else {
            log.debug("退款申请失败");
            return (String)resultMap.get("err_code") + ":" + (String)resultMap.get("err_code_des");
        }
    }

    public static String wxRefundMini(WxPayConfig wxPayConfig, RefundModel refundModel, Function callBack) {
        String xmlStr = "";
        String resultXml = "";
        new HashMap();
        double refundFee = refundModel.getRefundAmount().doubleValue();
        double totalFee = refundModel.getTotalFee().doubleValue();
        String total_fee = Integer.toString((int)(totalFee * 100.0));
        String refund_fee = Integer.toString((int)(refundFee * 100.0));
        String refund_desc = refundModel.getRefundReason();
        Map<String, String> map = new HashMap();
        map.put("appid", wxPayConfig.getMiniAppId());
        map.put("mch_id", wxPayConfig.getMchId());
        map.put("nonce_str", UUIDUtil.getUUID());
        map.put("transaction_id", refundModel.getTradeNo());
        map.put("out_refund_no", refundModel.getRefundNo());
        map.put("out_trade_no", refundModel.getOrderNo());
        map.put("total_fee", total_fee);
        map.put("refund_fee", refund_fee);
        map.put("refund_desc", refund_desc);
        map.put("notify_url", wxPayConfig.getCallFunc());

        Map resultMap;
        try {
            xmlStr = SignUtil.getMD5Sign(map, wxPayConfig.getKey(), wxPayConfig.getFieldSign());
            map.put("sign", xmlStr);
            resultXml = ClientCustomSSL.doRefund(wxPayConfig, MapUtil.mapToXml(map));
            resultMap = MapUtil.xml2Map(resultXml);
        } catch (Exception var15) {
            Exception e = var15;
            log.debug("调用退款接口失败");
            return e.getMessage();
        }

        if (((String)resultMap.get("return_code")).equals(wxPayConfig.getResponseSuccess()) && ((String)resultMap.get("result_code")).equals(wxPayConfig.getResponseSuccess())) {
            log.debug("退款申请成功");
            callBack.apply(resultMap);
            return "success";
        } else {
            log.debug("退款申请失败");
            return (String)resultMap.get("err_code") + ":" + (String)resultMap.get("err_code_des");
        }
    }

    public static Map<String, String> entPay(String openId, BigDecimal amount, String outBatchNo, WxPayConfig wxPayConfig) throws Exception {
        int transitionAmount = (new BigDecimal(100)).multiply(amount).setScale(0, 4).intValue();
        Map<String, Object> dataMap = new HashMap();
        dataMap.put("appid", wxPayConfig.getAppId());
        dataMap.put("out_batch_no", outBatchNo);
        dataMap.put("batch_name", "提现");
        dataMap.put("batch_remark", "提现");
        dataMap.put("total_amount", transitionAmount);
        dataMap.put("total_num", 1);
        List<Map<String, Object>> transferDetailList = new ArrayList();
        Map<String, Object> transferDetail = new HashMap();
        transferDetail.put("out_detail_no", UUIDUtil.getUUID());
        transferDetail.put("transfer_amount", transitionAmount);
        transferDetail.put("transfer_remark", "提现");
        transferDetail.put("openid", openId);
        transferDetailList.add(transferDetail);
        dataMap.put("transfer_detail_list", transferDetailList);
        String resStr = HttpUtil.postTransBatRequest(wxPayConfig.getWithdrawToMerchantUrl(), JSONUtil.toJsonStr(dataMap), wxPayConfig.getSerialNo(), wxPayConfig.getMchId(), wxPayConfig.getPrivateKeyPath());
        log.info("提现返回结果：" + resStr);
        return processResponseXml(resStr, wxPayConfig.getKey(), wxPayConfig.getFieldSign());
    }

    public static Map<String, String> entPay(String openid, String outBatchNo, BigDecimal amount, WxPayConfig wxPayConfig) throws Exception {
        int transitionAmount = (new BigDecimal(100)).multiply(amount).setScale(0, 4).intValue();
        Map<String, String> parameterMap = new TreeMap();
        parameterMap.put("amount", String.valueOf(transitionAmount));
        parameterMap.put("check_name", "NO_CHECK");
        parameterMap.put("mch_appid", wxPayConfig.getAppId());
        parameterMap.put("mchid", wxPayConfig.getMchId());
        parameterMap.put("partner_trade_no", outBatchNo);
        parameterMap.put("nonce_str", WxPayUtils.generateNonceStr());
        parameterMap.put("openid", openid);
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            parameterMap.put("spbill_create_ip", localIp());
        } else {
            parameterMap.put("spbill_create_ip", requestAttributes.getRequest().getRemoteAddr());
        }

        parameterMap.put("desc", "提现");
        parameterMap.put("sign", WxPayUtils.generateSignature(parameterMap, wxPayConfig.getKey(), "MD5"));
        String reuqestXml = WxPayUtils.mapToXml(parameterMap);
        System.out.println("微信企业付款到零钱请求集合" + reuqestXml);
        String weixinPost = HttpUtil.HttpClientSSL(reuqestXml, wxPayConfig.getMchId(), wxPayConfig.getWithdrawToEnterpriseUrl(), wxPayConfig.getCertUrl());
        System.out.println("微信企业付款到零钱返回结果" + weixinPost);
        Map<String, String> resultMap = WxPayUtils.xmlToMap(weixinPost);
        return resultMap;
    }

    private static String localIp() {
        String ip = null;

        try {
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();

            while(allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = (NetworkInterface)allNetInterfaces.nextElement();
                List<InterfaceAddress> InterfaceAddress = netInterface.getInterfaceAddresses();
                Iterator var4 = InterfaceAddress.iterator();

                while(var4.hasNext()) {
                    InterfaceAddress add = (InterfaceAddress)var4.next();
                    InetAddress Ip = add.getAddress();
                    if (Ip != null && Ip instanceof Inet4Address) {
                        ip = Ip.getHostAddress();
                    }
                }
            }
        } catch (SocketException var7) {
        }

        return ip;
    }
}
